package bluetooth

import (
	"context"
	"fmt"
	"regexp"
	"sync"
	"time"

	"gitee.com/rw555/fdsmastergo/pkg/logger"
	"github.com/go-ble/ble"
	"github.com/go-ble/ble/examples/lib/dev"
	"go.uber.org/zap"
)

// DeviceFilter 设备过滤器
type DeviceFilter struct {
	NamePattern *regexp.Regexp // 设备名称正则匹配
	MinRSSI     int            // 最小信号强度
}

// Scanner 蓝牙扫描器
type Scanner struct {
	device      ble.Device
	isReady     bool
	stopChan    chan struct{}
	readyChan   chan struct{} // 用于通知设备就绪
	unreadyChan chan struct{} // 用于通知设备未就绪
	mutex       sync.RWMutex

	// 过滤器
	smokeFilter     *DeviceFilter // 烟感设备过滤器
	personnelFilter *DeviceFilter // 模拟人员设备过滤器

	// 设备发现回调
	onDeviceDiscovered func(device *ScannedDevice, deviceType string)
}

// NewScanner 创建蓝牙扫描器
func NewScanner(smokeFilter *DeviceFilter, personnelFilter *DeviceFilter) (*Scanner, error) {
	return &Scanner{
		stopChan:        make(chan struct{}),
		readyChan:       make(chan struct{}, 1),
		unreadyChan:     make(chan struct{}, 1),
		smokeFilter:     smokeFilter,
		personnelFilter: personnelFilter,
	}, nil
}

// filterDevice 检查设备是否符合过滤条件，并确定设备类型
func (s *Scanner) filterDevice(dev *ScannedDevice) string {
	if s.smokeFilter != nil {
		if s.smokeFilter.NamePattern != nil && !s.smokeFilter.NamePattern.MatchString(dev.Name) {
			return ""
		}
		if s.smokeFilter.MinRSSI != 0 && dev.RSSI < s.smokeFilter.MinRSSI {
			return ""
		}

		return DeviceTypeSmokeDetector

	} else if s.personnelFilter != nil {
		if s.personnelFilter.NamePattern != nil && !s.personnelFilter.NamePattern.MatchString(dev.Name) {
			return ""
		}
		if s.personnelFilter.MinRSSI != 0 && dev.RSSI < s.personnelFilter.MinRSSI {
			return ""
		}

		return DeviceTypePersonnel
	}

	// 不符合任何已知类型
	return ""
}

// Start 启动蓝牙扫描器
func (s *Scanner) Start() {
	go s.monitorDevice()
}

// Stop 停止蓝牙扫描器
func (s *Scanner) Stop() {
	close(s.stopChan)
}

// monitorDevice 监控蓝牙设备状态
func (s *Scanner) monitorDevice() {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	// 首次检查
	s.checkDevice()

	for {
		select {
		case <-s.stopChan:
			return
		case <-ticker.C:
			s.checkDevice()
		}
	}
}

// checkDevice 检查设备状态
func (s *Scanner) checkDevice() {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	// 尝试初始化设备
	if err := s.initDevice(); err != nil {
		if s.isReady {
			logger.SystemError("蓝牙设备异常", zap.Error(err))
			s.isReady = false
			s.device = nil
			select {
			case s.unreadyChan <- struct{}{}:
			default:
			}
		} else {
			logger.SystemError("蓝牙设备初始化失败", zap.Error(err))
		}
		return
	}

	// 检查设备是否正常
	if err := s.testDevice(); err != nil {
		logger.SystemError("蓝牙设备测试失败", zap.Error(err))
		s.isReady = false
		s.device = nil
		select {
		case s.unreadyChan <- struct{}{}:
		default:
		}
		return
	}

	// 设备正常
	if !s.isReady {
		logger.SystemInfo("蓝牙设备已就绪")
		s.isReady = true
		select {
		case s.readyChan <- struct{}{}:
		default:
		}
	}
}

// initDevice 初始化蓝牙设备
func (s *Scanner) initDevice() error {
	if s.device != nil {
		return nil
	}

	d, err := dev.NewDevice("default")
	if err != nil {
		return fmt.Errorf("初始化BLE设备失败: %w", err)
	}

	ble.SetDefaultDevice(d)
	s.device = d
	return nil
}

// testDevice 测试设备是否正常
func (s *Scanner) testDevice() error {
	// 执行一次短暂的扫描测试
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	err := ble.Scan(ctx, true, func(a ble.Advertisement) {}, nil)
	if err != nil && err != context.DeadlineExceeded {
		return fmt.Errorf("设备测试失败: %w", err)
	}
	return nil
}

// IsReady 检查设备是否就绪
func (s *Scanner) IsReady() bool {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return s.isReady
}

// WaitReady 等待设备就绪
func (s *Scanner) WaitReady() <-chan struct{} {
	return s.readyChan
}

// WaitUnready 等待设备未就绪
func (s *Scanner) WaitUnready() <-chan struct{} {
	return s.unreadyChan
}

// Scan 扫描BLE设备
func (s *Scanner) Scan(duration time.Duration) error {
	// 获取设备引用前加锁
	s.mutex.RLock()
	device := s.device
	s.mutex.RUnlock()

	if device == nil {
		return fmt.Errorf("BLE设备未初始化")
	}

	ctx := ble.WithSigHandler(context.WithTimeout(context.Background(), duration))

	advHandler := func(a ble.Advertisement) {
		if a.Connectable() {
			dev := &ScannedDevice{
				Name:     a.LocalName(),
				MAC:      a.Addr().String(),
				RSSI:     a.RSSI(),
				TxPower:  a.TxPowerLevel(),
				LastSeen: time.Now(),
			}

			// 应用过滤器确定设备类型
			deviceType := s.filterDevice(dev)
			if deviceType != "" {
				dev.Type = deviceType

				// 调用设备发现回调
				if s.onDeviceDiscovered != nil {
					s.onDeviceDiscovered(dev, deviceType)
				}
			}
		}
	}

	err := ble.Scan(ctx, true, advHandler, nil)
	if err != nil && err != context.DeadlineExceeded {
		s.mutex.Lock()
		if s.device == device {
			s.isReady = false
			s.device = nil
			select {
			case s.unreadyChan <- struct{}{}:
			default:
			}
		}
		s.mutex.Unlock()
		return fmt.Errorf("BLE扫描失败: %w", err)
	}

	return nil
}

// SetDeviceDiscoveredCallback 设置设备发现回调
func (s *Scanner) SetDeviceDiscoveredCallback(callback func(device *ScannedDevice, deviceType string)) {
	s.onDeviceDiscovered = callback
}
